-- Autor: Ariel Pacay
-- Legajo N° 121237-0
-- Curso K2081
-- Docente a cargo: Valeria Pennella
-- Campus - Noche
-- TP2 A Volar!

type Vuelo = (Integer,String,CiudadHorario,CiudadHorario,Double)
type CiudadHorario = (String,(Fecha,Hora))
type Fecha = (Integer,Integer,Integer)
type Hora = (Integer,Integer)
type Combinacion = (CiudadHorario,CiudadHorario)

-- algunos vuelos para probar
lan4170 = (4170, "lan", ("buenos aires",((2013,12,24),(17,15))),("londres",((2013,12,25),(5,15))), 4000.0)
iberia5800 = (5800, "iberia", ("londres",((2013,12,25),(5,45))), ("barcelona",((2013,12,25),(6,55))), 500.0)
iberia5801 = (5801, "iberia", ("londres",((2013,12,25),(7,00))), ("barcelona",((2013,12,25),(8,10))), 500.0)
xM5801 = (5801, "iberia", ("londres",((2013,12,26),(7,00))), ("roma",((2013,12,26),(8,10))), 500.0)
type PromosEmpresa = ([Char],[([Char],Vuelo -> Bool,Double -> Double)])
type Promo = ([Char],Vuelo -> Bool,Double -> Double)
empresaDeLasPromos::PromosEmpresa->[Char]
empresaDeLasPromos (empresa,_) = empresa

promosDeLaEmpresa::PromosEmpresa->[Promo]
promosDeLaEmpresa(_,promos)= promos

codigo (codigo, _, _, _, _) = codigo
aerolinea (_, aerolinea, _, _, _) = aerolinea
salida::Vuelo->CiudadHorario
salida (_, _, salida, _, _) = salida
ciudad (laCiudad,_) = laCiudad
llegada (_, _, _, llegada, _) = llegada
precioBase (_, _, _, _, precio) = precio
fechaHora (_, unaFechaHora) = unaFechaHora
fecha( unaFecha,_)=unaFecha

valorBase (_,_,_,_,elValor) = elValor

-- Se dispone de una función mágica horasDeDiferencia que se puede usar
-- 		horasDeDiferencia ((2013,10,23),(17,15)) ((2013,10,23),(18,45)) 1.5

-- Una ciudad se considera comercial si la tenemos en esta lista
ciudadesComerciales = ["buenos aires", "londres", "nueva york", "tokio"]


-- Tenemos una lista con todas las promociones que ofrecen las aerolíneas
-- una promoción es (nombre, criterio de validez, cálculo para el descuento)
--promociones = [ ("iberia",[("navidad", esNavidad.fechaDe salida, porcentaje 50), ("buenasNoches",(\vuelo->fechaDe salida vuelo < fechaDe llegada vuelo),(*0.1))]), ("lan", [("comercial", vueloComercial, porcentaje 10)])]
promociones = [("iberia",[("navidad", esNavidad.fechaDe salida, porcentaje 50)]),("lan", [("comercial", vueloComercial, porcentaje 10)])]

porcentaje::Double->Double->Double
porcentaje n total = (total * n)/ 100

-- se conocen los siguientes impuestos que se aplican.
afip::(Double->Double)
afip = (*1.2)
tasa::(Double->Double)
tasa = (+100.0)

-- 1a
esNavidad::Fecha->Bool
esNavidad (_,12,25) = True
esNavidad (_,_,_) = False

--1b
fechaDe::(Vuelo->CiudadHorario)->Vuelo->Fecha
fechaDe unaFuncionComoLlegadaOSalida unVuelo = fecha (fechaHora (unaFuncionComoLlegadaOSalida unVuelo))

--1c
vueloComercial esteVuelo = esComercial (salida esteVuelo) && esComercial (llegada esteVuelo)
esComercial::CiudadHorario->Bool
esComercial estaCiudadHorario = any (== (ciudad estaCiudadHorario)) ciudadesComerciales

--Alegria! (n.n)
--Ej2
codigosDeVuelosSalientes unaCiudad listaDeVuelos = map codigo [esteVuelo|esteVuelo <- listaDeVuelos,ciudad (salida (esteVuelo)) == unaCiudad]

--3 no tiene abc
todosLlegan unaCiudad unaListadeVuelos = all (unaCiudad==) (map (ciudad.llegada) unaListadeVuelos)

horasDeDiferencia::(Fecha,Hora)->(Fecha,Hora)->Double
horasDeDiferencia _ _ = 1.5

-- Ejercicio Quatro pomelo
economica::Vuelo->Double
economica _ = 100.0

business::Vuelo->Double
business unVuelo | vueloComercial unVuelo = 200
                     | otherwise = 350
primera::Vuelo->Double
primera unVuelo = min 500 ((horasDeDiferencia  (fechaHora (salida unVuelo)) (fechaHora (llegada unVuelo)))*100)
  

--Ejercicio 5
promocionesDeLaEmpresa::[Char]->[Promo]
promocionesDeLaEmpresa unaEmpresa = head (map promosDeLaEmpresa (filter ((unaEmpresa==).empresaDeLasPromos)  promociones))

precio::(Vuelo->Double)->Vuelo->Double
precio unPlus unVuelo = (+) (valorBase unVuelo) ((-) (unPlus unVuelo) (resolverPromociones (promocionesDeLaEmpresa (aerolinea unVuelo)) unVuelo))

resolverPromociones::[Promo]->Vuelo->Double
resolverPromociones promos elVuelo= sum [resolverPromocion unaPromo elVuelo|unaPromo<-promos] --(hacer la cuenta (filter promoVale ))  

resolverPromocion::Promo->Vuelo->Double
resolverPromocion (nombrePromo,aplicaA,aDescontar) unVuelo | aplicaA unVuelo = (aDescontar (valorBase unVuelo))
                                                           | otherwise = 0

-- Ej 6
conImpuestos unPlus unVuelo unaLista = aplicarEnOrden unaLista (precio unPlus unVuelo)
aplicarEnOrden::[(Double->Double)]->Double->Double
aplicarEnOrden [] unValor = unValor
aplicarEnOrden (x:[]) unValor = x unValor
aplicarEnOrden (x:xs) unValor = aplicarEnOrden xs ((x) unValor)


--Ej 7
--otra vez problemas con recursividad =(
combinaciones::[Vuelo]->[Combinacion]
combinaciones [x] = []
combinaciones (unVuelo:otroVuelo:cola) = [(llegada unVuelo, salida otroVuelo)] ++ (combinaciones (otroVuelo:cola))

--Ej 8
--Sale sumatoriaDe funcionQueTransformaListaDeParametro2EnListaDeEnteros listaDeParametro2

sumatoriaDe::(a->Double)->[a]->Double
sumatoriaDe funcionLoca listaLoca = sum ((map funcionLoca) listaLoca)
--h
precioTotal unPlus unaLista = sumatoriaDe (\x -> conImpuestos unPlus x [tasa]) unaLista
--g
tiempoDeCombinaciones unaLista = sumatoriaDe (\((_,x),(_,y)) -> horasDeDiferencia x y) (combinaciones unaLista)

--Ej 9
listaDeVuelosInfinitos::[Vuelo]->[Vuelo]
listaDeVuelosInfinitos [] = listaDeVuelosInfinitos [lan4170, iberia5801]
listaDeVuelosInfinitos unaLista = unaLista++(listaDeVuelosInfinitos unaLista )

--Infinito en ej 8 Se en el renglon de abajo queda esperando a terminar esperando a que termine de sumar algo que no terminará nunca. No para hasta que interrumpo el calculo
--Infinito en ej 7 Empieza a escribir la lista infinita, y no para hasta que interrumpo el calculo.
--Infinito en ej 3 En cuanto encuentra 1 solo elemento que no cumpla con el all sale.
--Esto es porque hace el analisis en modo lazy, esto significa que no analiza mas que lo que necesita al momento que lo necesita. No espera a toda la sentencia para definir el valor de verdad, o realizar un calculo.